home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / ELECTRON / PCB_DESI / 1540.ZIP / PCBCA110.ZIP / PCBPRINT.C < prev    next >
C/C++ Source or Header  |  1992-08-27  |  37KB  |  1,411 lines

  1. /*
  2. ** printed circuit board printer, Copyright (C) Randy Nevin 1989, 1990.
  3. **
  4. ** you may give this software to anyone, make as many copies as you like, and
  5. ** post it on public computer bulletin boards and file servers. you may not
  6. ** sell it or charge any fee for distribution (except for media and postage),
  7. ** remove this comment or the copyright notice from the code, or claim that
  8. ** you wrote this code or anything derived from it. you may modify the code as
  9. ** much as you want (please document clearly with comments, and maintain the
  10. ** coding style), but programs which are derived from this one are subject to
  11. ** the conditions stated here. i am providing this code so that people can
  12. ** learn from it, so if you distribute it, please include source code, not
  13. ** just executables. contact me to report bugs or suggest enhancements; i do
  14. ** not guarantee support, but i will make an effort to help you, and i want to
  15. ** act as a central clearing house for future versions. you should contact me
  16. ** before undertaking a significant development effort, to avoid reinventing
  17. ** the wheel. if you come up with an enhancement you consider particularly
  18. ** useful, i would appreciate being informed so that it can be incorporated in
  19. ** future versions. my address is: Randy Nevin, 24135 SE 16th PL, Issaquah,
  20. ** WA 98027, USA. this code is available directly from the author; just send a
  21. ** 360k floppy and a self-addressed floppy mailer with sufficient postage.
  22. **
  23. ** HISTORY
  24. ** (name        date        description)
  25. ** ----------------------------------------------------
  26. ** randy nevin        3/4/89        initial version
  27. ** randy nevin        3/4/89        released version 1.00
  28. ** randy nevin        4/22/89        implemented /H and /V switches to
  29. **                    distinguish between hp laser jet
  30. **                    commands and vector-oriented commands;
  31. **                    the new vector-oriented commands
  32. **                    should be easy to translate into
  33. **                    postscript or other graphics printer
  34. **                    languages such as hpgl, and are
  35. **                    human-readable
  36. ** randy nevin        4/27/89        released version 1.10
  37. ** randy nevin        1/18/92        1.20, changed 18x18->15x15
  38. */
  39.  
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include "cell.h"
  44.  
  45. /*
  46. ** usage: PCBPRINT [/H] [/V] [/P] [/L] [/Rn] [/Zm] infile
  47. **
  48. ** /P indicates portrait orientation (paper is longer from top to bottom), and
  49. ** /L indicates landscape orientation (paper is longer side-to-side). only one
  50. ** of /P and /L can be present. n is the laser printer resolution (75, 100,
  51. ** 150, or 300) and m is the zoom factor (0, 1, 2, or 3). the defaults are:
  52. ** /P /R150 /Z1. this program creates 6 output files (H, T, B, HT, HB, and
  53. ** HTB). each of these files can be fed to a hewlett-packard laser printer to
  54. ** produce a picture of part or all of the routed printed circuit board. H
  55. ** contains commands to print only the holes and routing holes. T and B
  56. ** contain commands to print only the top-side or bottom-side traces,
  57. ** respectively. HT and HB are the same, but also include the holes, and HTB
  58. ** contains everything (holes, top-side traces, and bottom-side traces).
  59. **
  60. ** /H selects hewlett-packard laser printer commands, and is the default.
  61. ** /V selects vector-oriented commands; if it is selected, none of the other
  62. ** switches are available. when /V is selected, the output files are as above,
  63. ** but consist of the following types of lines:
  64. **    1) DIMENSION(rowmax, colmax)
  65. **    2) LINE(row1, col1, row2, col2)
  66. **    3) CIRCLE(row, col, radius)
  67. ** all parameters are real numbers, and specified in mils (1/1000 of an inch).
  68. ** DIMENSION tells the maximum row and column values that will be encountered.
  69. ** LINE specifies the endpoints of a line. CIRCLE gives a circle center and
  70. ** radius. here is a blow-up of one 50-mil-by-50-mil cell, with certain points
  71. ** of interest labeled by their position relative to the origin (0.0,0.0):
  72. **
  73. **    A---------------B---------------C
  74. **    |                               |
  75. **    |             **D**             | 
  76. **    |           *       *           |
  77. **    |         E           F         |
  78. **    |       *               *       | 
  79. **    G      H        I        J      K
  80. **    |       *               *       | 
  81. **    |         L           M         |
  82. **    |           *       *           |
  83. **    |             **N**             | 
  84. **    |                               |
  85. **    O---------------P---------------Q
  86. **
  87. **    A = ( 50,      0       )
  88. **    B = ( 50,      25      )
  89. **    C = ( 50,      50      )
  90. **    D = ( 37.5,    25      )
  91. **    E = ( 33.8388, 16.1612 )
  92. **    F = ( 33.8388, 33.8388 )
  93. **    G = ( 25,      0       )
  94. **    H = ( 25,      12.5    )
  95. **    I = ( 25,      25      )
  96. **    J = ( 25,      37.5    )
  97. **    K = ( 25,      50      )
  98. **    L = ( 16.1612, 16.1612 )
  99. **    M = ( 16.1612, 33.8388 )
  100. **    N = ( 12.5,    25      )
  101. **    O = ( 0,       0       )
  102. **    P = ( 0,       25      )
  103. **    Q = ( 0,       50      )
  104. */
  105.  
  106. /* markers that hole-related traces have been processed */
  107. #define NOT_NORTH        0x00000200L    /* upward        */
  108. #define NOT_NORTHEAST        0x00000400L    /* upward and right    */
  109. #define NOT_EAST        0x00000800L    /* to the right        */
  110. #define NOT_SOUTHEAST        0x00001000L    /* downward and right    */
  111. #define NOT_SOUTH        0x00002000L    /* downward        */
  112. #define NOT_SOUTHWEST        0x00004000L    /* downward and left    */
  113. #define NOT_WEST        0x00008000L    /* to the left        */
  114. #define NOT_NORTHWEST        0x00010000L    /* upward and left    */
  115. #define NOT_ALL            ( NOT_NORTH \
  116.                 | NOT_NORTHEAST \
  117.                 | NOT_EAST \
  118.                 | NOT_SOUTHEAST \
  119.                 | NOT_SOUTH \
  120.                 | NOT_SOUTHWEST \
  121.                 | NOT_WEST \
  122.                 | NOT_NORTHWEST )
  123.  
  124. #define MAXZOOM    3    /* maximum zoom number; minimum is 0 */
  125.  
  126. #define ZOOM0    3    /* 3x3 dots per cell    */
  127. #define ZOOM1    6    /* 6x6 dots per cell    */
  128. #define ZOOM2    10    /* 10x10 dots per cell    */
  129. #define ZOOM3    15    /* 15x15 dots per cell    */
  130.  
  131. #define HPLASERJET    0    /* hp laser jet commands    */
  132. #define VECTOR        1    /* vector-oriented commands    */
  133.  
  134. static int size[MAXZOOM+1] = { ZOOM0, ZOOM1, ZOOM2, ZOOM3 };
  135.  
  136. #define H    1    /* holes                */
  137. #define T    2    /* top-side traces            */
  138. #define B    4    /* bottom-side traces            */
  139. #define HT    (H+T)    /* holes and top-side traces        */
  140. #define HB    (H+B)    /* holes and bottom-side traces        */
  141. #define HTB    (H+T+B)    /* holes, top- and bottom-side traces    */
  142.  
  143. static int style;    /* 0 = /H, 1 = /V                */
  144. static int currnt;    /* current image type (one of the six above)    */
  145. static int orient;    /* 0=portrait, 1=landscape            */
  146. static int resol;    /* resolution (one of 75,100,150,300)        */
  147. static int zoom;    /* 0=3x3, 1=6x6, 2=10x10, 3=15x15        */
  148. static int nbytes;    /* number of bytes per image row        */
  149.  
  150. int JustBoard = 1; /* only need the board data structure */
  151.  
  152. extern int Nrows, Ncols; /* board dimensions */
  153.  
  154. extern void InitBoard( void );
  155. extern long GetCell( int, int, int );
  156. extern void SetCell( int, int, int, long );
  157.  
  158. void main( int, char *[] );
  159. static void dofile( char *, int );
  160. static void prolog( FILE * );
  161. static void epilog( FILE * );
  162. static void doimage( FILE * );
  163. static void dovector( FILE * );
  164. static void trace( FILE *, int, int, int, int, int, int, int, int );
  165. static void map( long, long, int, FILE * );
  166. static void initbit( void );
  167. static void flushbit( FILE * );
  168. static void outbit( int, FILE * );
  169.  
  170. void main ( argc, argv ) /* input routed board, output laser printer files */
  171.     int argc;
  172.     char *argv[];
  173.     {
  174.     char *self, *p;
  175.     register int r, c;
  176.     int i1, i2, i3, i4, i, j;
  177.     FILE *fp;
  178.     long x;
  179.     char oset, rset, zset;
  180.  
  181.     printf( "Copyright (C) Randy Nevin, 1989, 1990. Version 1.20\n" );
  182.     printf( "See source code for rights granted.\n\n" );
  183.     style = HPLASERJET;
  184.     orient = 0; /* portrait mode */
  185.     resol = 150; /* 150 dots per inch */
  186.     zoom = 1; /* 6x6 cells */
  187.     oset = rset = zset = 0; /* so far, just defaults */
  188.     self = argv[0];
  189.     /* get rid of initial part of path */
  190.     if ((p = strrchr( self, '\\' )) || (p = strrchr( self, ':' )))
  191.         self = ++p;
  192.     /* get rid of extension */
  193.     if ((p = strrchr( self, '.' )) && !stricmp( p, ".EXE" ))
  194.         *p = 0;
  195.     if (argc < 2 || argc > 5) { /* need infile and up to 4 switches */
  196.         fprintf( stderr,
  197.             "usage: %s [/H] [/V] [/P] [/L] [/Rn] [/Zm] infile\n",
  198.             self );
  199.         fprintf( stderr, " H = hp laser jet commands (default)\n" );
  200.         fprintf( stderr, " V = vector-oriented commands\n" );
  201.         fprintf( stderr, " P = portrait orientation\n" );
  202.         fprintf( stderr, " L = landscape orientation\n" );
  203.         fprintf( stderr, " n = resolution (75,100,150,300)\n" );
  204.         fprintf( stderr, " m = zoom (0,1,2,3)\n" );
  205.         exit( -1 );
  206.         }
  207.     for (i = 1; i < argc-1; i++) { /* process switches */
  208.         if (!stricmp( argv[i], "/h" ))
  209.             style = HPLASERJET;
  210.         else if (!stricmp( argv[i], "/v" ))
  211.             style = VECTOR;
  212.         else if (!stricmp( argv[i], "/p" )) {
  213.             if (oset)
  214.                 fprintf( stderr, "duplicate orientation %s\n",
  215.                     argv[i] );
  216.             else {
  217.                 oset = 1;
  218.                 orient = 0;
  219.                 }
  220.             }
  221.         else if (!stricmp( argv[i], "/l" )) {
  222.             if (oset)
  223.                 fprintf( stderr, "duplicate orientation %s\n",
  224.                     argv[i] );
  225.             else {
  226.                 oset = 1;
  227.                 orient = 1;
  228.                 }
  229.             }
  230.         else if (*argv[i] == '/' && (*(argv[i]+1) == 'R'
  231.             || *(argv[i]+1) == 'r')) {
  232.             if (rset)
  233.                 fprintf( stderr, "duplicate resolution %s\n",
  234.                     argv[i] );
  235.             else {
  236.                 rset = 1;
  237.                 resol = atoi( argv[i]+2 );
  238.                 }
  239.             }
  240.         else if (*argv[i] == '/' && (*(argv[i]+1) == 'Z'
  241.             || *(argv[i]+1) == 'z')) {
  242.             if (zset)
  243.                 fprintf( stderr, "duplicate zoom %s\n",
  244.                     argv[i] );
  245.             else {
  246.                 zset = 1;
  247.                 zoom = atoi( argv[i]+2 );
  248.                 }
  249.             }
  250.         else
  251.             fprintf( stderr, "unknown option %s\n", argv[i] );
  252.         }
  253.     if (!(fp = fopen( argv[argc-1], "rb" ))) {
  254.         fprintf( stderr, "can't open %s\n", argv[argc-1] );
  255.         exit( -1 );
  256.         }
  257.     /* fetch the board dimensions */
  258.     if ((i = getc( fp )) == EOF || (j = getc( fp )) == EOF) {
  259.         fprintf( stderr, "premature eof\n" );
  260.         exit( -1 );
  261.         }
  262.     Nrows = (i & 0xFF) | ((j << 8) & 0xFF00);
  263.     if ((i = getc( fp )) == EOF || (j = getc( fp )) == EOF) {
  264.         fprintf( stderr, "premature eof\n" );
  265.         exit( -1 );
  266.         }
  267.     Ncols = (i & 0xFF) | ((j << 8) & 0xFF00);
  268.     InitBoard(); /* allocate memory for data structures */
  269.     for (r = 0; r < Nrows; r++) { /* read in the board, row by column */
  270.         for (c = 0; c < Ncols; c++) {
  271.             /* first do top-side */
  272.             if ((i1 = getc( fp )) == EOF
  273.                 || (i2 = getc( fp )) == EOF
  274.                 || (i3 = getc( fp )) == EOF
  275.                 || (i4 = getc( fp )) == EOF) {
  276.                 fprintf( stderr, "premature eof\n" );
  277.                 exit( -1 );
  278.                 }
  279.             x = (long)i1;
  280.             x |= (((long)i2) << 8);
  281.             x |= (((long)i3) << 16);
  282.             x |= (((long)i4) << 24);
  283.             SetCell( r, c, TOP, x );
  284.             /* then do bottom-side */
  285.             if ((i1 = getc( fp )) == EOF
  286.                 || (i2 = getc( fp )) == EOF
  287.                 || (i3 = getc( fp )) == EOF
  288.                 || (i4 = getc( fp )) == EOF) {
  289.                 fprintf( stderr, "premature eof\n" );
  290.                 exit( -1 );
  291.                 }
  292.             x = (long)i1;
  293.             x |= (((long)i2) << 8);
  294.             x |= (((long)i3) << 16);
  295.             x |= (((long)i4) << 24);
  296.             SetCell( r, c, BOTTOM, x );
  297.             }
  298.         }
  299.     nbytes = (Ncols * size[zoom] + 7) / 8;
  300.     dofile( "H",   H   );
  301.     dofile( "T",   T   );
  302.     dofile( "B",   B   );
  303.     dofile( "HT",  HT  );
  304.     dofile( "HB",  HB  );
  305.     dofile( "HTB", HTB );
  306.     exit( 0 );
  307.     }
  308.  
  309. static void dofile ( p, i ) /* create a board image file */
  310.     char *p;
  311.     int i;
  312.     {
  313.     FILE *fp;
  314.  
  315.     printf( "producing %s image file\n", p );
  316.     currnt = i;
  317.     if (!(fp = fopen( p, "wb" ))) {
  318.         fprintf( stderr, "can't open %s\n", p );
  319.         exit( -1 );
  320.         }
  321.     if (style == HPLASERJET) {
  322.         prolog( fp ); /* initial laser printer commands */    
  323.         doimage( fp ); /* create the board image */
  324.         epilog( fp ); /* final laser printer commands */
  325.         }
  326.     else if (style == VECTOR)
  327.         dovector( fp ); /* create the board image */
  328.     else {
  329.         fprintf( stderr, "internal error\n" );
  330.         exit( -1 );
  331.         }
  332.     if (fclose( fp )) {
  333.         fprintf( stderr, "can't close %s\n", p );
  334.         exit( -1 );
  335.         }
  336.     }
  337.  
  338. static void prolog ( fp ) /* output initial laser printer commands */
  339.     register FILE *fp;
  340.     {
  341.     putc( 0x1B, fp );        /* <esc> */
  342.     putc( 'E', fp );        /* reset */
  343.     putc( 0x1B, fp );        /* <esc> */
  344.     fprintf( fp, "&l%dO", orient );    /* set image orientation */
  345.     putc( 0x1B, fp );        /* <esc> */
  346.     fprintf( fp, "&a10R" );        /* cursor to row 10 */
  347.     putc( 0x1B, fp );        /* <esc> */
  348.     fprintf( fp, "&a10C" );        /* cursor to column 10 */
  349.     putc( 0x1B, fp );        /* <esc> */
  350.     fprintf( fp, "*t%dR", resol );    /* set resolution in dots per inch */
  351.     putc( 0x1B, fp );        /* <esc> */
  352.     fprintf( fp, "*r1A" );        /* start graphics at cursor */
  353.     if (ferror( fp ))
  354.         fprintf( stderr, "output error; disk might be full\n" );
  355.     }
  356.  
  357. static void epilog ( fp ) /* output final laser printer commands */
  358.     register FILE *fp;
  359.     {
  360.     putc( 0x1B, fp );    /* <esc> */
  361.     fprintf( fp, "*rB" );    /* end graphics */
  362.     putc( 0x12, fp );    /* formfeed to eject paper */
  363.     putc( 0x1B, fp );    /* <esc> */
  364.     putc( 'E', fp );    /* reset */
  365.     if (ferror( fp ))
  366.         fprintf( stderr, "output error; disk might be full\n" );
  367.     }
  368.  
  369. static void doimage ( fp ) /* create the board image, row by column */
  370.     FILE *fp;
  371.     {
  372.     register int r, c;
  373.     int ir;
  374.     long x, y;
  375.  
  376.     for (r = Nrows-1; r >= 0; r--) { /* each row */
  377.         for (ir = size[zoom]-1; ir >= 0; ir--) { /* each scan line */
  378.             putc( 0x1B, fp );    /* <esc> */
  379.             fprintf( fp, "*b%dW", nbytes );
  380.             initbit();
  381.             for (c = 0; c < Ncols; c++) {
  382.                 x = GetCell( r, c, TOP );
  383.                 y = GetCell( r, c, BOTTOM );
  384.                 map( x, y, ir, fp );
  385.                 }
  386.             flushbit( fp );
  387.             }
  388.         }
  389.     if (ferror( fp ))
  390.         fprintf( stderr, "output error; disk might be full\n" );
  391.     }
  392.  
  393. /* statement formats */
  394. static char dimstmt[] = "DIMENSION(%d.%d, %d.%d)\r\n";
  395. static char cirstmt[] = "CIRCLE(%d.%d, %d.%d, %d.%d)\r\n";
  396. static char linstmt[] = "LINE(%d.%d, %d.%d, %d.%d, %d.%d)\r\n";
  397.  
  398. static void dovector ( fp ) /* create the board image, row by column */
  399.     FILE *fp;
  400.     {
  401.     register int r, c;
  402.     int r50, c50;
  403.     long x;
  404.  
  405.     fprintf( fp, dimstmt, Nrows*50, 0, Ncols*50, 0 );
  406.     for (r = 0, r50 = 0; r < Nrows; r++, r50 += 50)
  407.         for (c = 0, c50 = 0; c < Ncols; c++, c50 += 50) {
  408.             x = GetCell( r, c, TOP );
  409.             if (x & HOLE) {
  410.                 if (currnt & H)
  411.                     fprintf( fp, cirstmt, r50+25, 0,
  412.                         c50+25, 0, 12, 5 );
  413.                 if (currnt & T) {
  414. /*
  415. ** NOTE: when the trace exits to a corner, we should check which of the
  416. ** 3 adjoining cells it actually goes into. for now, we assume it goes
  417. ** into the diagonal one. if this is a false assumption, the cases
  418. ** below for NORTHEAST, SOUTHEAST, SOUTHWEST, and NORTHWEST will require
  419. ** more checking before the trace() can be started.
  420. */
  421.                     if ((x&(HOLE_NORTH|NOT_NORTH))
  422.                         == HOLE_NORTH)
  423.                         trace( fp, r+1, c,
  424.                             TOP, FROM_SOUTH,
  425.                             r50+37, 5,
  426.                             c50+25, 0 );
  427.                     if ((x&(HOLE_NORTHEAST|NOT_NORTHEAST))
  428.                         == HOLE_NORTHEAST)
  429.                         trace( fp, r+1, c+1,
  430.                             TOP, FROM_SOUTHWEST,
  431.                             r50+33, 8388,
  432.                             c50+33, 8388 );
  433.                     if ((x&(HOLE_EAST|NOT_EAST))
  434.                         == HOLE_EAST)
  435.                         trace( fp, r, c+1,
  436.                             TOP, FROM_WEST,
  437.                             r50+25, 0,
  438.                             c50+37, 5 );
  439.                     if ((x&(HOLE_SOUTHEAST|NOT_SOUTHEAST))
  440.                         == HOLE_SOUTHEAST)
  441.                         trace( fp, r-1, c+1,
  442.                             TOP, FROM_NORTHWEST,
  443.                             r50+16, 1612,
  444.                             c50+33, 8388 );
  445.                     if ((x&(HOLE_SOUTH|NOT_SOUTH))
  446.                         == HOLE_SOUTH)
  447.                         trace( fp, r-1, c,
  448.                             TOP, FROM_NORTH,
  449.                             r50+12, 5,
  450.                             c50+25, 0 );
  451.                     if ((x&(HOLE_SOUTHWEST|NOT_SOUTHWEST))
  452.                         == HOLE_SOUTHWEST)
  453.                         trace( fp, r-1, c-1,
  454.                             TOP, FROM_NORTHEAST,
  455.                             r50+16, 1612,
  456.                             c50+16, 1612 );
  457.                     if ((x&(HOLE_WEST|NOT_WEST))
  458.                         == HOLE_WEST)
  459.                         trace( fp, r, c-1,
  460.                             TOP, FROM_EAST,
  461.                             r50+25, 0,
  462.                             c50+12, 5 );
  463.                     if ((x&(HOLE_NORTHWEST|NOT_NORTHWEST))
  464.                         == HOLE_NORTHWEST)
  465.                         trace( fp, r+1, c-1,
  466.                             TOP, FROM_SOUTHEAST,
  467.                             r50+33, 8388,
  468.                             c50+16, 1612 );
  469.                     }
  470.                 if (currnt & B) {
  471.                     x = GetCell( r, c, BOTTOM );
  472.                     if ((x&(HOLE_NORTH|NOT_NORTH))
  473.                         == HOLE_NORTH)
  474.                         trace( fp, r+1, c,
  475.                             BOTTOM,
  476.                             FROM_SOUTH,
  477.                             r50+37, 5,
  478.                             c50+25, 0 );
  479.                     if ((x&(HOLE_NORTHEAST|NOT_NORTHEAST))
  480.                         == HOLE_NORTHEAST)
  481.                         trace( fp, r+1, c+1,
  482.                             BOTTOM,
  483.                             FROM_SOUTHWEST,
  484.                             r50+33, 8388,
  485.                             c50+33, 8388 );
  486.                     if ((x&(HOLE_EAST|NOT_EAST))
  487.                         == HOLE_EAST)
  488.                         trace( fp, r, c+1,
  489.                             BOTTOM,
  490.                             FROM_WEST,
  491.                             r50+25, 0,
  492.                             c50+37, 5 );
  493.                     if ((x&(HOLE_SOUTHEAST|NOT_SOUTHEAST))
  494.                         == HOLE_SOUTHEAST)
  495.                         trace( fp, r-1, c+1,
  496.                             BOTTOM,
  497.                             FROM_NORTHWEST,
  498.                             r50+16, 1612,
  499.                             c50+33, 8388 );
  500.                     if ((x&(HOLE_SOUTH|NOT_SOUTH))
  501.                         == HOLE_SOUTH)
  502.                         trace( fp, r-1, c,
  503.                             BOTTOM,
  504.                             FROM_NORTH,
  505.                             r50+12, 5,
  506.                             c50+25, 0 );
  507.                     if ((x&(HOLE_SOUTHWEST|NOT_SOUTHWEST))
  508.                         == HOLE_SOUTHWEST)
  509.                         trace( fp, r-1, c-1,
  510.                             BOTTOM,
  511.                             FROM_NORTHEAST,
  512.                             r50+16, 1612,
  513.                             c50+16, 1612 );
  514.                     if ((x&(HOLE_WEST|NOT_WEST))
  515.                         == HOLE_WEST)
  516.                         trace( fp, r, c-1,
  517.                             BOTTOM,
  518.                             FROM_EAST,
  519.                             r50+25, 0,
  520.                             c50+12, 5 );
  521.                     if ((x&(HOLE_NORTHWEST|NOT_NORTHWEST))
  522.                         == HOLE_NORTHWEST)
  523.                         trace( fp, r+1, c-1,
  524.                             BOTTOM,
  525.                             FROM_SOUTHEAST,
  526.                             r50+33, 8388,
  527.                             c50+16, 1612 );
  528.                     }
  529.                 }
  530.             }
  531.     for (r = 0; r < Nrows; r++) /* reset hole-done indicator bits */
  532.         for (c = 0; c < Ncols; c++) {
  533.             x = GetCell( r, c, TOP );
  534.             if (x & HOLE) {
  535.                 SetCell( r, c, TOP, x&(~NOT_ALL) );
  536.                 x = GetCell( r, c, BOTTOM );
  537.                 SetCell( r, c, BOTTOM, x&(~NOT_ALL) );
  538.                 }
  539.             }
  540.     }
  541.  
  542. static void trace ( fp, r, c, s, d, lr, lrf, lc, lcf )
  543.     /* draw a trace with LINE statements */
  544.     FILE *fp;
  545.     register int r, c;
  546.     int s, d, lr, lrf, lc, lcf;
  547.     {
  548.     int r50, c50, a;
  549.     long x;
  550.  
  551.     /*
  552.     ** (r,c,s) gives the current cell; (r50,c50) maintains (r*50,c*50)
  553.     ** so we don't have to keep doing multiplies; d gives the FROM_x
  554.     ** direction we entered this cell from; a gives the FROM_x
  555.     ** direction (angle) of the line currently being built;
  556.     ** (lr.lrf,lc.lcf) gives the mil location (whole and fractional
  557.     ** part, maintained separately so we don't have to do floating
  558.     ** point math) of the last point connected.
  559.     */
  560.  
  561.     r50 = r*50;
  562.     c50 = c*50;
  563.     a = d; /* angle of trace is same as initial direction */
  564.     for (;;) { /* search for the terminating HOLE */
  565.         x = GetCell( r, c, s );
  566.         if (x & HOLE) { /* found it? */
  567. /*
  568. ** NOTE: we should really include a check here that the proper HOLE_x
  569. ** bit is turned on. for now, we assume it is.
  570. */
  571.             switch (d) { /* output the last LINE */
  572.             case FROM_NORTH:
  573.                 if (a != FROM_NORTH) {
  574.                     fprintf( fp, linstmt,
  575.                         lr, lrf, lc, lcf,
  576.                         r50+50, 0, c50+25, 0 );
  577.                     lr = r50+50;
  578.                     lc = c50+25;
  579.                     lrf = lcf = 0;
  580.                     }
  581.                 fprintf( fp, linstmt,
  582.                     lr, lrf, lc, lcf,
  583.                     r50+37, 5, c50+25, 0 );
  584.                 SetCell( r, c, s, x|NOT_NORTH );
  585.                 break;
  586.             case FROM_NORTHEAST:
  587.                 fprintf( fp, linstmt,
  588.                     lr, lrf, lc, lcf,
  589.                     r50+33, 8388, c50+33, 8388 );
  590.                 SetCell( r, c, s, x|NOT_NORTHEAST );
  591.                 break;
  592.             case FROM_EAST:
  593.                 if (a != FROM_EAST) {
  594.                     fprintf( fp, linstmt,
  595.                         lr, lrf, lc, lcf,
  596.                         r50+25, 0, c50+50, 0 );
  597.                     lr = r50+25;
  598.                     lc = c50+50;
  599.                     lrf = lcf = 0;
  600.                     }
  601.                 fprintf( fp, linstmt,
  602.                     lr, lrf, lc, lcf,
  603.                     r50+25, 0, c50+37, 5 );
  604.                 SetCell( r, c, s, x|NOT_EAST );
  605.                 break;
  606.             case FROM_SOUTHEAST:
  607.                 fprintf( fp, linstmt,
  608.                     lr, lrf, lc, lcf,
  609.                     r50+16, 1612, c50+33, 8388 );
  610.                 SetCell( r, c, s, x|NOT_SOUTHEAST );
  611.                 break;
  612.             case FROM_SOUTH:
  613.                 if (a != FROM_SOUTH) {
  614.                     fprintf( fp, linstmt,
  615.                         lr, lrf, lc, lcf,
  616.                         r50, 0, c50+25, 0 );
  617.                     lr = r50;
  618.                     lc = c50+25;
  619.                     lrf = lcf = 0;
  620.                     }
  621.                 fprintf( fp, linstmt,
  622.                     lr, lrf, lc, lcf,
  623.                     r50+12, 5, c50+25, 0 );
  624.                 SetCell( r, c, s, x|NOT_SOUTH );
  625.                 break;
  626.             case FROM_SOUTHWEST:
  627.                 fprintf( fp, linstmt,
  628.                     lr, lrf, lc, lcf,
  629.                     r50+16, 1612, c50+16, 1612 );
  630.                 SetCell( r, c, s, x|NOT_SOUTHWEST );
  631.                 break;
  632.             case FROM_WEST:
  633.                 if (a != FROM_WEST) {
  634.                     fprintf( fp, linstmt,
  635.                         lr, lrf, lc, lcf,
  636.                         r50+25, 0, c50, 0 );
  637.                     lr = r50+25;
  638.                     lc = c50;
  639.                     lrf = lcf = 0;
  640.                     }
  641.                 fprintf( fp, linstmt,
  642.                     lr, lrf, lc, lcf,
  643.                     r50+25, 0, c50+12, 5 );
  644.                 SetCell( r, c, s, x|NOT_WEST );
  645.                 break;
  646.             case FROM_NORTHWEST:
  647.                 fprintf( fp, linstmt,
  648.                     lr, lrf, lc, lcf,
  649.                     r50+33, 8388, c50+16, 1612 );
  650.                 SetCell( r, c, s, x|NOT_NORTHWEST );
  651.                 break;
  652.             default:
  653.                 fprintf( stderr, "internal error\n" );
  654.                 exit( -1 );
  655.                 break;
  656.                 }
  657.             return;
  658.             }
  659.  
  660.         /*
  661.         ** not a HOLE; keep walking along the trace. if the angle is
  662.         ** still right, just move along. otherwise, output a LINE
  663.         ** statement for any turns that are made, reset the last
  664.         ** point connected, and go to the next cell.
  665.         */
  666.  
  667.         switch (d) {
  668.         case FROM_NORTH:
  669.             if (x & LINE_VERTICAL) {
  670.                 if (a != FROM_NORTH) {
  671.                     fprintf( fp, linstmt,
  672.                         lr, lrf, lc, lcf,
  673.                         r50+50, 0, c50+25, 0 );
  674.                     lr = r50+50;
  675.                     lc = c50+25;
  676.                     lrf = lcf = 0;
  677.                     a = FROM_NORTH;
  678.                     }
  679.                 r--;  r50 -= 50;
  680.                 }
  681.             else if (x & CORNER_NORTHEAST) {
  682.                 if (a != FROM_NORTHWEST) {
  683.                     fprintf( fp, linstmt,
  684.                         lr, lrf, lc, lcf,
  685.                         r50+50, 0, c50+25, 0 );
  686.                     lr = r50+50;
  687.                     lc = c50+25;
  688.                     lrf = lcf = 0;
  689.                     a = FROM_NORTHWEST;
  690.                     }
  691.                 c++;  c50 += 50;
  692.                 d = FROM_WEST;
  693.                 }
  694.             else if (x & CORNER_NORTHWEST) {
  695.                 if (a != FROM_NORTHEAST) {
  696.                     fprintf( fp, linstmt,
  697.                         lr, lrf, lc, lcf,
  698.                         r50+50, 0, c50+25, 0 );
  699.                     lr = r50+50;
  700.                     lc = c50+25;
  701.                     lrf = lcf = 0;
  702.                     a = FROM_NORTHEAST;
  703.                     }
  704.                 c--;  c50 -= 50;
  705.                 d = FROM_EAST;
  706.                 }
  707.             else if (x & (BENT_NtoSE | BENT_NtoSW)) {
  708.                 if (a != FROM_NORTH) {
  709.                     fprintf( fp, linstmt,
  710.                         lr, lrf, lc, lcf,
  711.                         r50+50, 0, c50+25, 0 );
  712.                     lr = r50+50;
  713.                     lc = c50+25;
  714.                     lrf = lcf = 0;
  715.                     }
  716.                 fprintf( fp, linstmt,
  717.                     lr, lrf, lc, lcf,
  718.                     r50+25, 0, c50+25, 0 );
  719.                 lr = r50+25;
  720.                 lc = c50+25;
  721.                 lrf = lcf = 0;
  722.                 r--;  r50 -= 50;
  723.                 if (x & BENT_NtoSE) {
  724.                     d = a = FROM_NORTHWEST;
  725.                     c++;  c50 += 50;
  726.                     }
  727.                 else {
  728.                     d = a = FROM_NORTHEAST;
  729.                     c--;  c50 -= 50;
  730.                     }
  731.                 }
  732.             else if (x & (SHARP_NtoNE | SHARP_NtoNW)) {
  733.                 if (a != FROM_NORTH) {
  734.                     fprintf( fp, linstmt,
  735.                         lr, lrf, lc, lcf,
  736.                         r50+50, 0, c50+25, 0 );
  737.                     lr = r50+50;
  738.                     lc = c50+25;
  739.                     lrf = lcf = 0;
  740.                     }
  741.                 fprintf( fp, linstmt,
  742.                     lr, lrf, lc, lcf,
  743.                     r50+25, 0, c50+25, 0 );
  744.                 lr = r50+25;
  745.                 lc = c50+25;
  746.                 lrf = lcf = 0;
  747.                 r++;  r50 += 50;
  748.                 if (x & SHARP_NtoNE) {
  749.                     d = a = FROM_SOUTHWEST;
  750.                     c++;  c50 += 50;
  751.                     }
  752.                 else {
  753.                     d = a = FROM_SOUTHEAST;
  754.                     c--;  c50 -= 50;
  755.                     }
  756.                 }
  757.             else {
  758.                 fprintf( stderr, "internal error\n" );
  759.                 exit( -1 );
  760.                 }
  761.             break;
  762.         case FROM_NORTHEAST:
  763.             if (x & DIAG_NEtoSW) {
  764.                 r--;  r50 -= 50;
  765.                 c--;  c50 -= 50;
  766.                 }
  767.             else if (x & (BENT_StoNE | BENT_WtoNE)) {
  768.                 fprintf( fp, linstmt,
  769.                     lr, lrf, lc, lcf,
  770.                     r50+25, 0, c50+25, 0 );
  771.                 lr = r50+25;
  772.                 lc = c50+25;
  773.                 lrf = lcf = 0;
  774.                 if (x & BENT_StoNE) {
  775.                     d = a = FROM_NORTH;
  776.                     r--;  r50 -= 50;
  777.                     }
  778.                 else {
  779.                     d = a = FROM_EAST;
  780.                     c--;  c50 -= 50;
  781.                     }
  782.                 }
  783.             else if (x & (ANGLE_NEtoSE | ANGLE_NWtoNE)) {
  784.                 fprintf( fp, linstmt,
  785.                     lr, lrf, lc, lcf,
  786.                     r50+25, 0, c50+25, 0 );
  787.                 lr = r50+25;
  788.                 lc = c50+25;
  789.                 lrf = lcf = 0;
  790.                 if (x & ANGLE_NEtoSE) {
  791.                     d = a = FROM_NORTHWEST;
  792.                     r--;  r50 -= 50;
  793.                     c++;  c50 += 50;
  794.                     }
  795.                 else {
  796.                     d = a = FROM_SOUTHEAST;
  797.                     r++;  r50 += 50;
  798.                     c--;  c50 -= 50;
  799.                     }
  800.                 }
  801.             else if (x & (SHARP_NtoNE | SHARP_EtoNE)) {
  802.                 fprintf( fp, linstmt,
  803.                     lr, lrf, lc, lcf,
  804.                     r50+25, 0, c50+25, 0 );
  805.                 lr = r50+25;
  806.                 lc = c50+25;
  807.                 lrf = lcf = 0;
  808.                 if (x & SHARP_NtoNE) {
  809.                     d = a = FROM_SOUTH;
  810.                     r++;  r50 += 50;
  811.                     }
  812.                 else {
  813.                     d = a = FROM_WEST;
  814.                     c++;  c50 += 50;
  815.                     }
  816.                 }
  817.             else {
  818.                 fprintf( stderr, "internal error\n" );
  819.                 exit( -1 );
  820.                 }
  821.             break;
  822.         case FROM_EAST:
  823.             if (x & LINE_HORIZONTAL) {
  824.                 if (a != FROM_EAST) {
  825.                     fprintf( fp, linstmt,
  826.                         lr, lrf, lc, lcf,
  827.                         r50+25, 0, c50+50, 0 );
  828.                     lr = r50+25;
  829.                     lc = c50+50;
  830.                     lrf = lcf = 0;
  831.                     a = FROM_EAST;
  832.                     }
  833.                 c--;  c50 -= 50;
  834.                 }
  835.             else if (x & CORNER_NORTHEAST) {
  836.                 if (a != FROM_SOUTHEAST) {
  837.                     fprintf( fp, linstmt,
  838.                         lr, lrf, lc, lcf,
  839.                         r50+25, 0, c50+50, 0 );
  840.                     lr = r50+25;
  841.                     lc = c50+50;
  842.                     lrf = lcf = 0;
  843.                     a = FROM_SOUTHEAST;
  844.                     }
  845.                 r++;  r50 += 50;
  846.                 d = FROM_SOUTH;
  847.                 }
  848.             else if (x & CORNER_SOUTHEAST) {
  849.                 if (a != FROM_NORTHEAST) {
  850.                     fprintf( fp, linstmt,
  851.                         lr, lrf, lc, lcf,
  852.                         r50+25, 0, c50+50, 0 );
  853.                     lr = r50+25;
  854.                     lc = c50+50;
  855.                     lrf = lcf = 0;
  856.                     a = FROM_NORTHEAST;
  857.                     }
  858.                 r--;  r50 -= 50;
  859.                 d = FROM_NORTH;
  860.                 }
  861.             else if (x & (BENT_EtoSW | BENT_EtoNW)) {
  862.                 if (a != FROM_EAST) {
  863.                     fprintf( fp, linstmt,
  864.                         lr, lrf, lc, lcf,
  865.                         r50+25, 0, c50+50, 0 );
  866.                     lr = r50+25;
  867.                     lc = c50+50;
  868.                     lrf = lcf = 0;
  869.                     }
  870.                 fprintf( fp, linstmt,
  871.                     lr, lrf, lc, lcf,
  872.                     r50+25, 0, c50+25, 0 );
  873.                 lr = r50+25;
  874.                 lc = c50+25;
  875.                 lrf = lcf = 0;
  876.                 c--;  c50 -= 50;
  877.                 if (x & BENT_EtoSW) {
  878.                     d = a = FROM_NORTHEAST;
  879.                     r--;  r50 -= 50;
  880.                     }
  881.                 else {
  882.                     d = a = FROM_SOUTHEAST;
  883.                     r++;  r50 += 50;
  884.                     }
  885.                 }
  886.             else if (x & (SHARP_EtoNE | SHARP_EtoSE)) {
  887.                 if (a != FROM_EAST) {
  888.                     fprintf( fp, linstmt,
  889.                         lr, lrf, lc, lcf,
  890.                         r50+25, 0, c50+50, 0 );
  891.                     lr = r50+25;
  892.                     lc = c50+50;
  893.                     lrf = lcf = 0;
  894.                     }
  895.                 fprintf( fp, linstmt,
  896.                     lr, lrf, lc, lcf,
  897.                     r50+25, 0, c50+25, 0 );
  898.                 lr = r50+25;
  899.                 lc = c50+25;
  900.                 lrf = lcf = 0;
  901.                 c++;  c50 += 50;
  902.                 if (x & SHARP_EtoNE) {
  903.                     d = a = FROM_SOUTHWEST;
  904.                     r++;  r50 += 50;
  905.                     }
  906.                 else {
  907.                     d = a = FROM_NORTHWEST;
  908.                     r--;  r50 -= 50;
  909.                     }
  910.                 }
  911.             else {
  912.                 fprintf( stderr, "internal error\n" );
  913.                 exit( -1 );
  914.                 }
  915.             break;
  916.         case FROM_SOUTHEAST:
  917.             if (x & DIAG_SEtoNW) {
  918.                 r++;  r50 += 50;
  919.                 c--;  c50 -= 50;
  920.                 }
  921.             else if (x & (BENT_NtoSE | BENT_WtoSE)) {
  922.                 fprintf( fp, linstmt,
  923.                     lr, lrf, lc, lcf,
  924.                     r50+25, 0, c50+25, 0 );
  925.                 lr = r50+25;
  926.                 lc = c50+25;
  927.                 lrf = lcf = 0;
  928.                 if (x & BENT_NtoSE) {
  929.                     d = a = FROM_SOUTH;
  930.                     r++;  r50 += 50;
  931.                     }
  932.                 else {
  933.                     d = a = FROM_EAST;
  934.                     c--;  c50 -= 50;
  935.                     }
  936.                 }
  937.             else if (x & (ANGLE_NEtoSE | ANGLE_SEtoSW)) {
  938.                 fprintf( fp, linstmt,
  939.                     lr, lrf, lc, lcf,
  940.                     r50+25, 0, c50+25, 0 );
  941.                 lr = r50+25;
  942.                 lc = c50+25;
  943.                 lrf = lcf = 0;
  944.                 if (x & ANGLE_NEtoSE) {
  945.                     d = a = FROM_SOUTHWEST;
  946.                     r++;  r50 += 50;
  947.                     c++;  c50 += 50;
  948.                     }
  949.                 else {
  950.                     d = a = FROM_NORTHEAST;
  951.                     r--;  r50 -= 50;
  952.                     c--;  c50 -= 50;
  953.                     }
  954.                 }
  955.             else if (x & (SHARP_EtoSE | SHARP_StoSE)) {
  956.                 fprintf( fp, linstmt,
  957.                     lr, lrf, lc, lcf,
  958.                     r50+25, 0, c50+25, 0 );
  959.                 lr = r50+25;
  960.                 lc = c50+25;
  961.                 lrf = lcf = 0;
  962.                 if (x & SHARP_EtoSE) {
  963.                     d = a = FROM_WEST;
  964.                     c++;  c50 += 50;
  965.                     }
  966.                 else {
  967.                     d = a = FROM_NORTH;
  968.                     r--;  r50 -= 50;
  969.                     }
  970.                 }
  971.             else {
  972.                 fprintf( stderr, "internal error\n" );
  973.                 exit( -1 );
  974.                 }
  975.             break;
  976.         case FROM_SOUTH:
  977.             if (x & LINE_VERTICAL) {
  978.                 if (a != FROM_SOUTH) {
  979.                     fprintf( fp, linstmt,
  980.                         lr, lrf, lc, lcf,
  981.                         r50, 0, c50+25, 0 );
  982.                     lr = r50;
  983.                     lc = c50+25;
  984.                     lrf = lcf = 0;
  985.                     a = FROM_SOUTH;
  986.                     }
  987.                 r++;  r50 += 50;
  988.                 }
  989.             else if (x & CORNER_SOUTHEAST) {
  990.                 if (a != FROM_SOUTHWEST) {
  991.                     fprintf( fp, linstmt,
  992.                         lr, lrf, lc, lcf,
  993.                         r50, 0, c50+25, 0 );
  994.                     lr = r50;
  995.                     lc = c50+25;
  996.                     lrf = lcf = 0;
  997.                     a = FROM_SOUTHWEST;
  998.                     }
  999.                 c++;  c50 += 50;
  1000.                 d = FROM_WEST;
  1001.                 }
  1002.             else if (x & CORNER_SOUTHWEST) {
  1003.                 if (a != FROM_SOUTHEAST) {
  1004.                     fprintf( fp, linstmt,
  1005.                         lr, lrf, lc, lcf,
  1006.                         r50, 0, c50+25, 0 );
  1007.                     lr = r50;
  1008.                     lc = c50+25;
  1009.                     lrf = lcf = 0;
  1010.                     a = FROM_SOUTHEAST;
  1011.                     }
  1012.                 c--;  c50 -= 50;
  1013.                 d = FROM_EAST;
  1014.                 }
  1015.             else if (x & (BENT_StoNE | BENT_StoNW)) {
  1016.                 if (a != FROM_SOUTH) {
  1017.                     fprintf( fp, linstmt,
  1018.                         lr, lrf, lc, lcf,
  1019.                         r50, 0, c50+25, 0 );
  1020.                     lr = r50;
  1021.                     lc = c50+25;
  1022.                     lrf = lcf = 0;
  1023.                     }
  1024.                 fprintf( fp, linstmt,
  1025.                     lr, lrf, lc, lcf,
  1026.                     r50+25, 0, c50+25, 0 );
  1027.                 lr = r50+25;
  1028.                 lc = c50+25;
  1029.                 lrf = lcf = 0;
  1030.                 r++;  r50 += 50;
  1031.                 if (x & BENT_StoNE) {
  1032.                     d = a = FROM_SOUTHWEST;
  1033.                     c++;  c50 += 50;
  1034.                     }
  1035.                 else {
  1036.                     d = a = FROM_SOUTHEAST;
  1037.                     c--;  c50 -= 50;
  1038.                     }
  1039.                 }
  1040.             else if (x & (SHARP_StoSE | SHARP_StoSW)) {
  1041.                 if (a != FROM_SOUTH) {
  1042.                     fprintf( fp, linstmt,
  1043.                         lr, lrf, lc, lcf,
  1044.                         r50, 0, c50+25, 0 );
  1045.                     lr = r50;
  1046.                     lc = c50+25;
  1047.                     lrf = lcf = 0;
  1048.                     }
  1049.                 fprintf( fp, linstmt,
  1050.                     lr, lrf, lc, lcf,
  1051.                     r50+25, 0, c50+25, 0 );
  1052.                 lr = r50+25;
  1053.                 lc = c50+25;
  1054.                 lrf = lcf = 0;
  1055.                 r--;  r50 -= 50;
  1056.                 if (x & SHARP_StoSE) {
  1057.                     d = a = FROM_NORTHWEST;
  1058.                     c++;  c50 += 50;
  1059.                     }
  1060.                 else {
  1061.                     d = a = FROM_NORTHEAST;
  1062.                     c--;  c50 -= 50;
  1063.                     }
  1064.                 }
  1065.             else {
  1066.                 fprintf( stderr, "internal error\n" );
  1067.                 exit( -1 );
  1068.                 }
  1069.             break;
  1070.         case FROM_SOUTHWEST:
  1071.             if (x & DIAG_NEtoSW) {
  1072.                 r++;  r50 += 50;
  1073.                 c++;  c50 += 50;
  1074.                 }
  1075.             else if (x & (BENT_NtoSW | BENT_EtoSW)) {
  1076.                 fprintf( fp, linstmt,
  1077.                     lr, lrf, lc, lcf,
  1078.                     r50+25, 0, c50+25, 0 );
  1079.                 lr = r50+25;
  1080.                 lc = c50+25;
  1081.                 lrf = lcf = 0;
  1082.                 if (x & BENT_NtoSW) {
  1083.                     d = a = FROM_SOUTH;
  1084.                     r++;  r50 += 50;
  1085.                     }
  1086.                 else {
  1087.                     d = a = FROM_WEST;
  1088.                     c++;  c50 += 50;
  1089.                     }
  1090.                 }
  1091.             else if (x & (ANGLE_SEtoSW | ANGLE_SWtoNW)) {
  1092.                 fprintf( fp, linstmt,
  1093.                     lr, lrf, lc, lcf,
  1094.                     r50+25, 0, c50+25, 0 );
  1095.                 lr = r50+25;
  1096.                 lc = c50+25;
  1097.                 lrf = lcf = 0;
  1098.                 if (x & ANGLE_SEtoSW) {
  1099.                     d = a = FROM_NORTHWEST;
  1100.                     r--;  r50 -= 50;
  1101.                     c++;  c50 += 50;
  1102.                     }
  1103.                 else {
  1104.                     d = a = FROM_SOUTHEAST;
  1105.                     r++;  r50 += 50;
  1106.                     c--;  c50 -= 50;
  1107.                     }
  1108.                 }
  1109.             else if (x & (SHARP_StoSW | SHARP_WtoSW)) {
  1110.                 fprintf( fp, linstmt,
  1111.                     lr, lrf, lc, lcf,
  1112.                     r50+25, 0, c50+25, 0 );
  1113.                 lr = r50+25;
  1114.                 lc = c50+25;
  1115.                 lrf = lcf = 0;
  1116.                 if (x & SHARP_StoSW) {
  1117.                     d = a = FROM_NORTH;
  1118.                     r--;  r50 -= 50;
  1119.                     }
  1120.                 else {
  1121.                     d = a = FROM_EAST;
  1122.                     c--;  c50 -= 50;
  1123.                     }
  1124.                 }
  1125.             else {
  1126.                 fprintf( stderr, "internal error\n" );
  1127.                 exit( -1 );
  1128.                 }
  1129.             break;
  1130.         case FROM_WEST:
  1131.             if (x & LINE_HORIZONTAL) {
  1132.                 if (a != FROM_WEST) {
  1133.                     fprintf( fp, linstmt,
  1134.                         lr, lrf, lc, lcf,
  1135.                         r50+25, 0, c50, 0 );
  1136.                     lr = r50+25;
  1137.                     lc = c50;
  1138.                     lrf = lcf = 0;
  1139.                     a = FROM_WEST;
  1140.                     }
  1141.                 c++;  c50 += 50;
  1142.                 }
  1143.             else if (x & CORNER_NORTHWEST) {
  1144.                 if (a != FROM_SOUTHWEST) {
  1145.                     fprintf( fp, linstmt,
  1146.                         lr, lrf, lc, lcf,
  1147.                         r50+25, 0, c50, 0 );
  1148.                     lr = r50+25;
  1149.                     lc = c50;
  1150.                     lrf = lcf = 0;
  1151.                     a = FROM_SOUTHWEST;
  1152.                     }
  1153.                 r++;  r50 += 50;
  1154.                 d = FROM_SOUTH;
  1155.                 }
  1156.             else if (x & CORNER_SOUTHWEST) {
  1157.                 if (a != FROM_NORTHWEST) {
  1158.                     fprintf( fp, linstmt,
  1159.                         lr, lrf, lc, lcf,
  1160.                         r50+25, 0, c50, 0 );
  1161.                     lr = r50+25;
  1162.                     lc = c50;
  1163.                     lrf = lcf = 0;
  1164.                     a = FROM_NORTHWEST;
  1165.                     }
  1166.                 r--;  r50 -= 50;
  1167.                 d = FROM_NORTH;
  1168.                 }
  1169.             else if (x & (BENT_WtoNE | BENT_WtoSE)) {
  1170.                 if (a != FROM_WEST) {
  1171.                     fprintf( fp, linstmt,
  1172.                         lr, lrf, lc, lcf,
  1173.                         r50+25, 0, c50, 0 );
  1174.                     lr = r50+25;
  1175.                     lc = c50;
  1176.                     lrf = lcf = 0;
  1177.                     }
  1178.                 fprintf( fp, linstmt,
  1179.                     lr, lrf, lc, lcf,
  1180.                     r50+25, 0, c50+25, 0 );
  1181.                 lr = r50+25;
  1182.                 lc = c50+25;
  1183.                 lrf = lcf = 0;
  1184.                 c++;  c50 += 50;
  1185.                 if (x & BENT_WtoNE) {
  1186.                     d = a = FROM_SOUTHWEST;
  1187.                     r++;  r50 += 50;
  1188.                     }
  1189.                 else {
  1190.                     d = a = FROM_NORTHWEST;
  1191.                     r--;  r50 -= 50;
  1192.                     }
  1193.                 }
  1194.             else if (x & (SHARP_WtoNW | SHARP_WtoSW)) {
  1195.                 if (a != FROM_WEST) {
  1196.                     fprintf( fp, linstmt,
  1197.                         lr, lrf, lc, lcf,
  1198.                         r50+25, 0, c50, 0 );
  1199.                     lr = r50+25;
  1200.                     lc = c50;
  1201.                     lrf = lcf = 0;
  1202.                     }
  1203.                 fprintf( fp, linstmt,
  1204.                     lr, lrf, lc, lcf,
  1205.                     r50+25, 0, c50+25, 0 );
  1206.                 lr = r50+25;
  1207.                 lc = c50+25;
  1208.                 lrf = lcf = 0;
  1209.                 c--;  c50 -= 50;
  1210.                 if (x & SHARP_WtoNW) {
  1211.                     d = a = FROM_SOUTHEAST;
  1212.                     r++;  r50 += 50;
  1213.                     }
  1214.                 else {
  1215.                     d = a = FROM_NORTHEAST;
  1216.                     r--;  r50 -= 50;
  1217.                     }
  1218.                 }
  1219.             else {
  1220.                 fprintf( stderr, "internal error\n" );
  1221.                 exit( -1 );
  1222.                 }
  1223.             break;
  1224.         case FROM_NORTHWEST:
  1225.             if (x & DIAG_SEtoNW) {
  1226.                 r--;  r50 -= 50;
  1227.                 c++;  c50 += 50;
  1228.                 }
  1229.             else if (x & (BENT_EtoNW | BENT_StoNW)) {
  1230.                 fprintf( fp, linstmt,
  1231.                     lr, lrf, lc, lcf,
  1232.                     r50+25, 0, c50+25, 0 );
  1233.                 lr = r50+25;
  1234.                 lc = c50+25;
  1235.                 lrf = lcf = 0;
  1236.                 if (x & BENT_EtoNW) {
  1237.                     d = a = FROM_WEST;
  1238.                     c++;  c50 += 50;
  1239.                     }
  1240.                 else {
  1241.                     d = a = FROM_NORTH;
  1242.                     r--;  r50 -= 50;
  1243.                     }
  1244.                 }
  1245.             else if (x & (ANGLE_SWtoNW | ANGLE_NWtoNE)) {
  1246.                 fprintf( fp, linstmt,
  1247.                     lr, lrf, lc, lcf,
  1248.                     r50+25, 0, c50+25, 0 );
  1249.                 lr = r50+25;
  1250.                 lc = c50+25;
  1251.                 lrf = lcf = 0;
  1252.                 if (x & ANGLE_SWtoNW) {
  1253.                     d = a = FROM_NORTHEAST;
  1254.                     r--;  r50 -= 50;
  1255.                     c--;  c50 -= 50;
  1256.                     }
  1257.                 else {
  1258.                     d = a = FROM_SOUTHWEST;
  1259.                     r++;  r50 += 50;
  1260.                     c++;  c50 += 50;
  1261.                     }
  1262.                 }
  1263.             else if (x & (SHARP_WtoNW | SHARP_NtoNW)) {
  1264.                 fprintf( fp, linstmt,
  1265.                     lr, lrf, lc, lcf,
  1266.                     r50+25, 0, c50+25, 0 );
  1267.                 lr = r50+25;
  1268.                 lc = c50+25;
  1269.                 lrf = lcf = 0;
  1270.                 if (x & SHARP_WtoNW) {
  1271.                     d = a = FROM_EAST;
  1272.                     c--;  c50 -= 50;
  1273.                     }
  1274.                 else {
  1275.                     d = a = FROM_SOUTH;
  1276.                     r++;  r50 += 50;
  1277.                     }
  1278.                 }
  1279.             else {
  1280.                 fprintf( stderr, "internal error\n" );
  1281.                 exit( -1 );
  1282.                 }
  1283.             break;
  1284.         default:
  1285.             fprintf( stderr, "internal error\n" );
  1286.             exit( -1 );
  1287.             break;
  1288.             }
  1289.         }
  1290.     }
  1291.  
  1292. struct x { /* group the bit templates for an object */
  1293.     long t;            /* the object type    */
  1294.     char t0[ZOOM0][ZOOM0];    /* tiny zoom template    */
  1295.     char t1[ZOOM1][ZOOM1];    /* small zoom template    */
  1296.     char t2[ZOOM2][ZOOM2];    /* medium zoom template    */
  1297.     char t3[ZOOM3][ZOOM3];    /* large zoom template    */
  1298.     };
  1299.  
  1300. extern struct x y1[]; /* hole templates */
  1301. extern struct x y2[]; /* hole-related templates */
  1302. extern struct x y3[]; /* non-hole-related templates */
  1303.  
  1304. extern int z1; /* number of hole types            */
  1305. extern int z2; /* number of hole-related types        */
  1306. extern int z3; /* number of non-hole-related types    */
  1307.  
  1308. #define domap1(v)    { int i; \
  1309.               for (i = 0; i < z1; i++) { \
  1310.                 if (v & (y1[i].t)) { \
  1311.                     if (zoom == 0) \
  1312.                         bit |= y1[i].t0[ir][ic]; \
  1313.                     else if (zoom == 1) \
  1314.                         bit |= y1[i].t1[ir][ic]; \
  1315.                     else if (zoom == 2) \
  1316.                         bit |= y1[i].t2[ir][ic]; \
  1317.                     else if (zoom == 3) \
  1318.                         bit |= y1[i].t3[ir][ic]; \
  1319.                     } \
  1320.                 if (bit) \
  1321.                     break; \
  1322.                 } }
  1323.  
  1324. #define domap2(v)    { int i; \
  1325.               for (i = 0; i < z2; i++) { \
  1326.                 if (v & (y2[i].t)) { \
  1327.                     if (zoom == 0) \
  1328.                         bit |= y2[i].t0[ir][ic]; \
  1329.                     else if (zoom == 1) \
  1330.                         bit |= y2[i].t1[ir][ic]; \
  1331.                     else if (zoom == 2) \
  1332.                         bit |= y2[i].t2[ir][ic]; \
  1333.                     else if (zoom == 3) \
  1334.                         bit |= y2[i].t3[ir][ic]; \
  1335.                     } \
  1336.                 if (bit) \
  1337.                     break; \
  1338.                 } }
  1339.  
  1340. #define domap3(v)    { int i; \
  1341.               for (i = 0; i < z3; i++) { \
  1342.                 if (v & (y3[i].t)) { \
  1343.                     if (zoom == 0) \
  1344.                         bit |= y3[i].t0[ir][ic]; \
  1345.                     else if (zoom == 1) \
  1346.                         bit |= y3[i].t1[ir][ic]; \
  1347.                     else if (zoom == 2) \
  1348.                         bit |= y3[i].t2[ir][ic]; \
  1349.                     else if (zoom == 3) \
  1350.                         bit |= y3[i].t3[ir][ic]; \
  1351.                     } \
  1352.                 if (bit) \
  1353.                     break; \
  1354.                 } }
  1355.  
  1356. static void map ( v0, v1, ir, fp ) /* map a cell to the image */
  1357.     long v0, v1;
  1358.     int ir;
  1359.     FILE *fp;
  1360.     {
  1361.     register int ic, bit;
  1362.  
  1363.     for (ic = 0; ic < size[zoom]; ic++) { /* do each scan column */
  1364.         bit = 0;
  1365.         if (v0 & HOLE) {
  1366.             if (currnt & H) /* plot holes? */
  1367.                 domap1( v0 );
  1368.             if (!bit && (currnt & T)) /* plot top-side? */
  1369.                 domap2( v0 );
  1370.             if (!bit && (currnt & B)) /* plot bottom-side? */
  1371.                 domap2( v1 );
  1372.             }
  1373.         else {
  1374.             if (v0 && (currnt & T)) /* plot top-side? */
  1375.                 domap3( v0 );
  1376.             if (!bit && v1 && (currnt & B)) /* plot bottom-side? */
  1377.                 domap3( v1 );
  1378.             }
  1379.         outbit( bit, fp );
  1380.         }
  1381.     }
  1382.  
  1383. static int shift; /* how far to shift next bit */
  1384. static char byte; /* the byte buffer */
  1385.  
  1386. static void initbit () { /* initialize bit output */
  1387.     byte = 0;
  1388.     shift = 7;
  1389.     }
  1390.  
  1391. static void flushbit ( fp ) /* flush bit output */
  1392.     FILE *fp;
  1393.     {
  1394.     if (shift != 7) /* buffer empty? */
  1395.         putc( byte, fp ); /* no, output partial byte */
  1396.     }
  1397.  
  1398. static void outbit( bit, fp ) /* output a bit using byte buffering */
  1399.     int bit;
  1400.     FILE *fp;
  1401.     {
  1402.     byte |= ((char)bit << shift);
  1403.     if (!shift) {
  1404.         putc( byte, fp );
  1405.         byte = 0;
  1406.         shift = 7;
  1407.         }
  1408.     else
  1409.         shift--;
  1410.     }
  1411.